package com.powerunion.datacollection.common;

import java.lang.reflect.*;
import java.util.*;

import org.apache.log4j.Logger;

import com.powerunion.util.log.LogHelper;

public class ObjectUtil {
  private static Logger logger = LogHelper.getInstance().getLogger(ObjectUtil.class);
  protected static List getFields(Class clazz) throws Exception {
    List fieldList = new ArrayList();
    Class clazzin = clazz;

    do {
      if (clazzin == null) {
        break;
      }

      fieldList.addAll(Arrays.asList(clazzin.getDeclaredFields()));

      clazzin = clazzin.getSuperclass();
    }
    while (true);

    return fieldList;
  }


  public static String toString(Object visitable) {
    try {
      if (Boolean.class.isAssignableFrom(visitable.getClass())) {
        return visitable.toString();
      }
      if (Byte.class.isAssignableFrom(visitable.getClass())) {
        return visitable.toString();
      }
      if (Character.class.isAssignableFrom(visitable.getClass())) {
        return visitable.toString();
      }
      if (Class.class.isAssignableFrom(visitable.getClass())) {
        return visitable.toString();
      }
      if (Double.class.isAssignableFrom(visitable.getClass())) {
        return visitable.toString();
      }
      if (Float.class.isAssignableFrom(visitable.getClass())) {
        return visitable.toString();
      }
      if (Integer.class.isAssignableFrom(visitable.getClass())) {
        return visitable.toString();
      }
      if (Long.class.isAssignableFrom(visitable.getClass())) {
        return visitable.toString();
      }
      if (Number.class.isAssignableFrom(visitable.getClass())) {
        return visitable.toString();
      }
      if (Short.class.isAssignableFrom(visitable.getClass())) {
        return visitable.toString();
      }
      if (String.class.isAssignableFrom(visitable.getClass())) {
        return visitable.toString();
      }
      if (StringBuffer.class.isAssignableFrom(visitable.getClass())) {
        return visitable.toString();
      }
      if (Void.class.isAssignableFrom(visitable.getClass())) {
        return visitable.toString();
      }
      if (List.class.isAssignableFrom(visitable.getClass())) {
        return visitable.toString();
      }
      if (Map.class.isAssignableFrom(visitable.getClass())) {
        return visitable.toString();
      }

      List fields = getFields(visitable.getClass());

      StringBuffer buffer = new StringBuffer();

      //Visitar los campos declarados en la clase visitable
      if (fields != null) {
        Field field = null;
        final int size = fields.size();
        for (int i = 0; i < size; i++) {
          field = (Field) fields.get(i);

          // No toma en cuenta el objeto ObjectUtil, ni atributos estaticos
          if (ObjectUtil.class.isAssignableFrom(field.getType()) ||
              Modifier.isStatic(field.getModifiers())) {
            continue;
          }

          field.setAccessible(true);

          buffer.append(field.getName() + "=" + field.get(visitable) + ",");
        }
      }

      if (buffer.length() > 0) {
        buffer.deleteCharAt(buffer.length() - 1);

      }
      return "{" + buffer.toString() + "}";
    }
    catch (Exception ignore) {
      logger.error(ignore);
      return "";
    }
  }

  public static boolean equals(Object visitable, Object obj) {
    try {
      Field field = null;
      List fields = getFields(visitable.getClass());

      if (fields != null) {
        final int size = fields.size();
        for (int i = 0; i < size; i++) {
          field = (Field) fields.get(i);

          // No toma en cuenta el objeto ObjectUtil
          if (ObjectUtil.class.isAssignableFrom(field.getType())) {
            continue;
          }

          field.setAccessible(true);

          if (!isEquals(field, visitable, obj)) {
            return false;
          }
        }
      }

      return true;
    }
    catch (Exception ignore) {
      logger.error(ignore);

      return false;
    }
  }

  protected static boolean isEquals(Field field, Object visitable, Object obj) {
    try {
      String fieldName = field.getName();
      String methodName = "get" +
          (fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1));

      Class[] methodParamTypes = new Class[] {};
      Object[] methodParamValues = new Object[] {};

      Method method1 = visitable.getClass().getMethod(methodName,
          methodParamTypes);
      method1.setAccessible(true);
      Object o1 = method1.invoke(visitable, methodParamValues);

      Method method2 = obj.getClass().getMethod(methodName, methodParamTypes);
      method2.setAccessible(true);
      Object o2 = method2.invoke(obj, methodParamValues);

      return o1 == null ? o2 == null : o1.equals(o2);
    }
    catch (Exception e) {
      e.printStackTrace();
      logger.error(e);
      return false;
    }
  }

  public static void finalize(Object visitable) {
    try {
      Field field = null;
      List fields = getFields(visitable.getClass());

      if (fields != null) {
        final int size = fields.size();
        for (int i = 0; i < size; i++) {
          field = (Field) fields.get(i);

          // No toma en cuenta el objeto ObjectUtil
          if (ObjectUtil.class.isAssignableFrom(field.getType())) {
            continue;
          }

          field.setAccessible(true);

          if (!field.getType().isPrimitive()) {
            field.set(visitable, null);
          }
        }
      }

      return;
    }
    catch (Exception ignore) {
      logger.error(ignore);
      return;
    }
  }


  public static int hashCode(Object visitable) {
    try {
      Field field = null;
      List fields = getFields(visitable.getClass());
      int hashcode = 0;
      Object obj = null;

      if (fields != null) {
        final int size = fields.size();
        for (int i = 0; i < size; i++) {
          field = (Field) fields.get(i);

          // No toma en cuenta el objeto ObjectUtil, ni atributos estaticos
          if (ObjectUtil.class.isAssignableFrom(field.getType())) {
            continue;
          }

          field.setAccessible(true);

          obj = field.get(visitable);
          hashcode = hashcode ^ (obj != null ? obj.hashCode() : 0);
        }
      }

      return hashcode;
    }
    catch (Exception ignore) {
      logger.error(ignore);
      return 0;
    }
  }

  public static String arrayToShallowString(Object[] array) {
    try {
      if (array == null) {
        return null;
      }

      StringBuffer buffer = new StringBuffer();

      buffer.append("{");
      for (int i = 0; i < array.length; i++) {
        if (i + 1 == array.length) {
          buffer.append(array[i]);
        }
        else {
          buffer.append(array[i]).append(",");
        }
      }
      buffer.append("}");

      return buffer.toString();
    }
    catch (Exception ignore) {
      logger.error(ignore);
      return "";
    }
  }

  public static String arrayToString(Object[] array) {
    try {
      if (array == null) {
        return null;
      }

      StringBuffer buffer = new StringBuffer();

      buffer.append("{");
      for (int i = 0; i < array.length; i++) {
        if (array[i] == null) {
          buffer.append("null");
        }
        else {
          if (i + 1 == array.length) {
            buffer.append(array[i].getClass().getName() + "=" +
                          ObjectUtil.toString(array[i]));
          }
          else {
            buffer.append(array[i].getClass().getName() + "=" +
                          ObjectUtil.toString(array[i])).append(",");
          }
        }
      }
      buffer.append("}");

      return buffer.toString();
    }
    catch (Exception ignore) {
      logger.error(ignore);
      return "";
    }
  }

  public static boolean isEmpty(Object visitable) {
    try {
      List fields = getFields(visitable.getClass());
      if (fields == null) {
        return false;
      }

      Field field = null;
      final int size = fields.size();
      for (int i = 0; i < size; i++) {
        field = (Field) fields.get(i);

        // No toma en cuenta el objeto ObjectUtil
        if (ObjectUtil.class.isAssignableFrom(field.getType())) {
          continue;
        }

        // Se marca como accesible el atributo de la clase
        field.setAccessible(true);

        Object value = field.get(visitable);

        if (value != null) {
          return false;
        }
      }

      return true;
    }
    catch (Exception ignore) {
      logger.error(ignore);
      return false;
    }
  }
  
//  public static Object json2Object(Object object,String jsonStr) {
//		JSONObject jsonObject = JSONObject.fromObject(jsonStr);
//		Object obj = (Object)JSONObject.toBean(jsonObject,Object.class);
//		return obj;
//  }
}
